MATH 318 Final Project: The Effect of World Cup on Stock Price and Trading Activity

library(tidyverse)
library(dplyr)
library(MASS)
library(lubridate)
library(stringr)
library(GGally)
library(knitr)
library(kableExtra)
library(tidyquant)
Loading required package: PerformanceAnalytics
Loading required package: xts
Loading required package: zoo

Attaching package: ‘zoo’

The following objects are masked from ‘package:base’:

    as.Date, as.Date.numeric


################################### WARNING ###################################
# We noticed you have dplyr installed. The dplyr lag() function breaks how    #
# base R's lag() function is supposed to work, which breaks lag(my_xts).      #
#                                                                             #
# Calls to lag(my_xts) that you enter or source() into this session won't     #
# work correctly.                                                             #
#                                                                             #
# All package code is unaffected because it is protected by the R namespace   #
# mechanism.                                                                  #
#                                                                             #
# Set `options(xts.warn_dplyr_breaks_lag = FALSE)` to suppress this warning.  #
#                                                                             #
# You can use stats::lag() to make sure you're not using dplyr::lag(), or you #
# can add conflictRules('dplyr', exclude = 'lag') to your .Rprofile to stop   #
# dplyr from breaking base R's lag() function.                                #
################################### WARNING ###################################

Attaching package: ‘xts’

The following objects are masked from ‘package:dplyr’:

    first, last


Attaching package: ‘PerformanceAnalytics’

The following object is masked from ‘package:graphics’:

    legend

Loading required package: quantmod
Loading required package: TTR
Registered S3 method overwritten by 'quantmod':
  method            from
  as.zoo.data.frame zoo 

Introduction

Our goal in this project was to explore the effect the FIFA World Cup has on the stock market. In researching to prepare, we found that the World Cup has a generally negative impact on the market. According to an article from MarketWatch, a country's average market return significantly drops after their team is eliminated from the Cup. The inverse can't be said for team wins, which leads to the overall market decreasing. Our interest was to investigate the market trends, specifically regarding the S&P 500, in relation to the times of World Cup games. 

Exploration

candleStick_plot<-function(symbol,from,to){
  tq_get(symbol,
        from = from,
        to = to,
        warnings = FALSE) %>% mutate(greenRed=ifelse(open-close>0,
                           "Red",
                           "Green")) %>%
    ggplot()+
    geom_segment(aes(x = date,
                     xend=date,
                     y =open,
                     yend =close,
                     colour=greenRed),
                 size=3)+
    theme_tq()+
    geom_segment(aes(x = date,
                     xend=date,
                     y =high,
                     yend =low,
                     colour=greenRed))+
    scale_color_manual(values=c("Forest Green","Red"))+
    ggtitle(paste0(symbol," (",from," - ",to,")"))+
    theme(legend.position ="none",
          axis.title.y = element_blank(),
          axis.title.x=element_blank(),
          axis.text.x = element_text(angle = 90, vjust = 0.5, hjust=1),
          plot.title= element_text(hjust=0.5))
}
candleStick_plot("SPY", from = '2002-05-31', to = '2002-06-30')
Warning: Using `size` aesthetic for lines was deprecated in ggplot2 3.4.0.
Please use `linewidth` instead.

candleStick_plot("SPY", from = '2006-06-09', to = '2006-07-09')

candleStick_plot("SPY", from = '2010-06-11',to = '2010-07-11')

candleStick_plot("SPY", from = '2014-06-12',to = '2014-07-13')

Load Data

spydata = as_tibble(read.csv("1_min_SPY_2008-2021.csv"))
worldcupmatches = as_tibble(read.csv("WorldCupMatches.csv"))

We were interested in looking at the general price of the market during the world cup, to confirm if our data shows the proposed trend of decreased price during the World Cup  we found in our research. To do this we used a graphing method called candlesticks plots. These plots show the average and variation of the price over a given month. Each plot spanned the month of the World Cup for the years 2002, 2006, 2010, 2014. Both the graph for 2002 and 2010 display a generally decreasing trend throughout the month. However, the 2006 and 2014 graphs instead show a general increase in price over time. To better understand trends in the data, we then looked closer at information from singular games. 



Helper Functions

Get Only Spy Data for a Specific Game

#Clean SpyData Per Game
getSpyDataWithinRangeofGame = function(spydata,game_date,range){
  rangeInSeconds = 60 * 60 * range
  return(filter(spydata, (date >= game_date - rangeInSeconds) & (date <= game_date + rangeInSeconds)))
}

Check if there is Spy data for a game

hasSpyDataWithinRangeOfGame = function(spydata, game_dates, range){
  list = c()
  for(game_date in 1:length(game_dates)){
    list = append(list, nrow(getSpyDataWithinRangeofGame(spydata, game_date = game_dates[game_date], range)) != 0)
  }
  return(list)
}

Get Spy Data combined with Game Data for a set of Games

#Clean Spydata Per Worldcup Returns a set of spydata with their corresponding game data
getSpyAndGameDataWithinWorldcup = function(worldcup, spydata, range){
  z = getSpyDataWithinRangeofGame(spydata, worldcup[[1,"Datetime"]], range)
  gamerow = worldcup[1,]
  for(colIndx in 1: ncol(gamerow)){
      colvalue = worldcup[[1, colIndx]]
      colname = colnames(worldcup)[colIndx]
      z[colname] = rep(colvalue, times= nrow(z))
  }
  z["time.from.game"] = as.numeric(difftime(z$date, worldcup[[1,"Datetime"]],units = "secs"))
  for(gameIndx in 2:nrow(worldcup)){
   x = getSpyDataWithinRangeofGame(spydata, worldcup[[gameIndx,"Datetime"]], range)
   gamerow = worldcup[gameIndx,]
   for(colIndx in 1: ncol(gamerow)){
      colvalue = worldcup[[gameIndx, colIndx]]
      colname = colnames(worldcup)[colIndx]
      x[colname] = rep(colvalue, times= nrow(x))
   }
   x["time.from.game"] = as.numeric(difftime(x$date, x$Datetime, units = "secs"))
  
   z = union_all(z,x)
  }
  return(z)
}

Get Spy Data combined with Game Data for a single game

#Gives Spydata and Difference from the game time for each worldcup game
getSpyAndGameDataForOneGame = function(spydata,worldcup, game_index, range){
  z = getSpyDataWithinRangeofGame(spydata, worldcup[[game_index,"Datetime"]], range)
  for(colIndx in 1: ncol(worldcup[game_index,])){
      colvalue = worldcup[[game_index, colIndx]]
      colname = colnames(worldcup)[colIndx]
      z[colname] = rep(colvalue, times= nrow(z))
  }
  z["time.from.game"] = as.numeric(difftime(z$date, rep(worldcup[[game_index,"Datetime"]], times = nrow(z)), units="secs"))
  return(z)
}

Cleaning Data

#Update 
spydata$date = as.POSIXct(spydata$date, format="%Y%m%d %H:%M:%S")

#Remove Rows containing NA's
cleaned_worldcupmatches = unique(worldcupmatches[!apply(is.na(worldcupmatches) | worldcupmatches == "", 1, all),])

#Convert Date and Time into POSIX EDT 
cleaned_worldcupmatches$Datetime = as.POSIXct(cleaned_worldcupmatches$Datetime, format = "%e %b %Y - %R") - 60 * 60

#Filter Games on the Weekend
cleaned_worldcupmatches = filter(cleaned_worldcupmatches, wday(as.Date(Datetime)) != 7 & wday(as.Date(Datetime)) != 1)

#Filter Games that have no corresponding Data
cleaned_worldcupmatches = add_column(cleaned_worldcupmatches,"HasSpyData" = hasSpyDataWithinRangeOfGame(spydata, cleaned_worldcupmatches$Datetime, 3))
cleaned_worldcupmatches = filter(cleaned_worldcupmatches, cleaned_worldcupmatches$HasSpyData == TRUE)

cleaned_worldcupmatches

Get Spy Data

#Get Spy data within 3 hours of the Game For both World cups
allspydata2014 = getSpyAndGameDataWithinWorldcup(filter(cleaned_worldcupmatches, Year==2014), spydata, 3)

allspydata2010 = getSpyAndGameDataWithinWorldcup(filter(cleaned_worldcupmatches, Year==2010), spydata, 3)

Normalizing the average price

#Normalize the Data so that we can compare fairly the growth of stock price
max.2014 = max(allspydata2014$average)
max.2010 = max(allspydata2010$average)


min.2014 = min(allspydata2014$average)
min.2010 = min(allspydata2010$average)

difference.2014 = (max.2014) - (min.2014)
difference.2010 = (max.2010) - (min.2010)
normalized2014average = (allspydata2014$average-min.2014)/difference.2014
normalized2010average = (allspydata2010$average-min.2010)/difference.2010


allspydata2014 = add_column(allspydata2014, "normalized.average" = normalized2014average)
allspydata2010 = add_column(allspydata2010, "normalized.average" = normalized2010average)

allspydata = union_all(allspydata2014, allspydata2010)

allspydata
NA

Before we could perform any tests on the data sets, we first had to take into account the stock price differences between the years 2010 and 2014. In order to normalize the stock price data, we had to split the data into each year and normalize the prices within that year. The method we chose to normalize the prices was subtracting the minimum price for that year from each price. This value was then divided by the difference between the maximum and minimum price for that year. Each normalized price is a value between zero and one. When interpreting these values, the closer the normalized value is to one, the closer the price is to the maximum for that year. Similarly, the closer the value is to zero, the closer the price is to the minimum for that year. By normalizing the prices for each year, we created an even playing field for price data, as they are all relative to the stock market climate in their given year.

Exploring the Relationship of Time and Volume

Let us explore the Correlation between the Time form game and the Price of the stock

Correlations

ggpairs(allspydata, columns = c("time.from.game", "average", "volume", "normalized.average"))

kable(cor(allspydata[, c(7,9,31,32)]))
volume average time.from.game normalized.average
volume 1.0000000 -0.4039908 0.0334462 0.1264736
average -0.4039908 1.0000000 0.2149680 -0.3961910
time.from.game 0.0334462 0.2149680 1.0000000 0.0158785
normalized.average 0.1264736 -0.3961910 0.0158785 1.0000000

After cleaning the data set, we computed the cross-correlations for the variables: time from the game, volume of trades, average price, and normalized average price. We were most interested in seeing how time from game affected volume of trades since volume shows stock productivity. We found that time from game had the highest correlation with average price, the correlation was 0.215. We also found that the correlation between time from game and volume was .033. These low values make sense given the data we had access to. We did not have data for commonly traded stocks by day traders. Nevertheless, we wanted to regress with volume as the dependent variable and time from game as the independent variable. After attempting multiple regression types, nonlinear regression gave us the best fit. 

Linear Regression

ggplot(allspydata) + geom_point(aes(time.from.game,normalized.average))

ggplot(allspydata, aes(time.from.game,log(volume))) + geom_point() + geom_smooth() + geom_vline(xintercept= 0, color = "red") + geom_vline(xintercept = 5400, color ="red")

The model we used for nonlinear regression is a Generalized Additive Model, also known as a GAM. A GAM is made up of splines, splines are smooth polynomial functions that cover a small range. These splines replace the beta coefficients that we normally see in linear regression, so that we can regress on nonlinear data. When we graph our nonlinear model over the volume data, we see that there is a spike in volume of trades 5000 seconds before the time of the game, which is about an hour and a half before the game. After this spike, there is a gradual increase once the game starts and the positive trend continues as the game finishes.



Sample Games from a World Cup

set.seed(100) 
samplesize = 10
worldcupmatches2014 = filter(cleaned_worldcupmatches, Year == 2014)
sampleworldcupgames = sample_n(worldcupmatches2014,size = samplesize)
game1 <- getSpyAndGameDataForOneGame(spydata, sampleworldcupgames, 1, 3)
volumesp1 <- ggplot(game1, mapping = aes(x=date, y=log(volume))) + geom_point(aes(color =average)) + geom_vline(xintercept= sampleworldcupgames$Datetime[1]) + ggtitle("Volume over Time, Sample Game 1")
volumesp1

game2 <- getSpyAndGameDataForOneGame(spydata, sampleworldcupgames, 2, 3)
volumesp2 <- ggplot(game2, mapping = aes(x=date, y=log(volume))) + geom_point(aes(color =average)) + geom_vline(xintercept= sampleworldcupgames$Datetime[2])+ ggtitle("Volume over Time, Sample Game 2")
volumesp2

#ERROR AGAIN WE DONT HAVE FULL DATA FOR THIS GAME
game3 <- getSpyAndGameDataForOneGame(spydata, sampleworldcupgames, 3, 3)
volumesp3 <- ggplot(game3, mapping = aes(x=date, y=log(volume))) + geom_point(aes(color =average)) + geom_vline(xintercept= sampleworldcupgames$Datetime[3])+ ggtitle("Volume over Time, Sample Game 3")
volumesp3

game4 <- getSpyAndGameDataForOneGame(spydata, sampleworldcupgames, 4, 3)
volumesp4 <- ggplot(game4, mapping = aes(x=date, y=log(volume))) + geom_point(aes(color =average)) + geom_vline(xintercept= sampleworldcupgames$Datetime[4])+ ggtitle("Volume over Time, Sample Game 4")

volumesp4

game5 <- getSpyAndGameDataForOneGame(spydata, sampleworldcupgames, 5, 3)
volumesp5 <- ggplot(game5, mapping = aes(x=date, y=log(volume))) + geom_point(aes(color =average)) + geom_vline(xintercept= sampleworldcupgames$Datetime[5])+ ggtitle("Volume over Time, Sample Game 5")
volumesp5

Price Scatter Plots

Using average price

pricesp1 <- ggplot(game1) + geom_point(mapping = aes(x=date, y=average), color ="red") + geom_vline(xintercept= sampleworldcupgames$Datetime[1])+ ggtitle("Price over Time, Sample Game 1")
pricesp1

pricesp2 <- ggplot(game2) + geom_point(mapping = aes(x=date, y=average), color ="red") + geom_vline(xintercept= sampleworldcupgames$Datetime[2])+ ggtitle("Price over Time, Sample Game 2")
pricesp2

#ISSUE BECAUSE WE DONT HAVE DATA FOR 16:00 and that is time of the game
pricesp3 <- ggplot(game3) + geom_point(mapping = aes(x=date, y=average), color ="red") + geom_vline(xintercept= sampleworldcupgames$Datetime[3])+ ggtitle("Price over Time, Sample Game 3")
pricesp3

pricesp4 <- ggplot(game4) + geom_point(mapping = aes(x=date, y=average), color ="red") + geom_vline(xintercept= sampleworldcupgames$Datetime[4])+ ggtitle("Price over Time, Sample Game 4")
pricesp4

pricesp5 <- ggplot(game5, aes(date)) + geom_point(aes(y=average, ), color ="red") + geom_vline(xintercept= sampleworldcupgames$Datetime[5])+ ggtitle("Price over Time, Sample Game 5")
pricesp5

We next looked at the volume of trading over a range of time from five sample games. Using ggpoint, we plotted the scatter plot of the market volume over a period of a few hours before and after the start of the game, and we indicated the start time with a vertical line on the graph. The values for volume are very large and varied, which makes the graphs difficult to read. To make them more digestible, we instead used the log of volume as the dependent variable, giving us smaller numbers. We found that, in general, there is a slight dip in the volume around the start time of the game. This agrees with findings from our research that stock market activity drops durring the World Cup as more attention is directed towards the games. We also used scatter plots to look at the average price of stocks over a range of time around the start time of sample games. As for the volume plots, we indicated the start time of the game with a vertical line on the graph. The figures show that the average price tends to drop just before the start of the game, and then increase. These trends in price lead us to explore the times it would be best to both buy and sell stocks.



Just USA Games

worldcupmatchesUSAhome = filter(cleaned_worldcupmatches, Home.Team.Name == "USA")
worldcupmatchesUSAaway = filter(cleaned_worldcupmatches, Away.Team.Name == "USA")
worldcupmatchesUSA <- union_all(worldcupmatchesUSAaway,worldcupmatchesUSAhome)
worldcupmatchesUSA
game1USA <- getSpyAndGameDataForOneGame(spydata, worldcupmatchesUSA, 1, 3)
volumesp1USA <- ggplot(game1USA) + geom_point(mapping = aes(x=date, y=log(volume)), color ="red") + geom_vline(xintercept= worldcupmatchesUSA$Datetime[1])+ ggtitle("Volume over Time, USA Game 1, 2010")
volumesp1USA

game2USA <- getSpyAndGameDataForOneGame(spydata, worldcupmatchesUSA, 2, 3)
volumesp2USA <- ggplot(game2USA) + geom_point(mapping = aes(x=date, y=log(volume)), color ="red") + geom_vline(xintercept= worldcupmatchesUSA$Datetime[2])+ ggtitle("Volume over Time, USA Game 2, 2014")
volumesp2USA

game3USA <- getSpyAndGameDataForOneGame(spydata, worldcupmatchesUSA, 3, 3)
volumesp3USA <- ggplot(game3USA) + geom_point(mapping = aes(x=date, y=volume), color ="red") + geom_vline(xintercept= worldcupmatchesUSA$Datetime[3])+ ggtitle("Volume over Time, USA Game 2, 2010")
volumesp3USA

game4USA <- getSpyAndGameDataForOneGame(spydata, worldcupmatchesUSA, 4, 3)
volumesp4USA <- ggplot(game4USA) + geom_point(mapping = aes(x=date, y=volume), color ="red") + geom_vline(xintercept= worldcupmatchesUSA$Datetime[4])+ ggtitle("Volume over Time, USA Game 1, 2014")
volumesp4USA

pricesp4USA <- ggplot(game4USA) + geom_point(mapping = aes(x=date, y=average), color ="red") + geom_vline(xintercept= worldcupmatchesUSA$Datetime[4])+ ggtitle("Price over Time, USA Game 1, 2014")
pricesp4USA

Is there a way to make money during World Cup Games?

What time should you look to sell?

price_list = c()
time_list = c()
for (game in 1:nrow(cleaned_worldcupmatches)) {
  price_game_data <- getSpyAndGameDataForOneGame(spydata, cleaned_worldcupmatches, game, 3)
  highestdatapoint = price_game_data[which.max(price_game_data$average),]
  highestpriceforgame <- highestdatapoint$average
  time <- highestdatapoint$"time.from.game"
  price_list = append(price_list, highestpriceforgame)
  time_list = append(time_list, time)
}
optimal_selling.df <- data.frame("price" = price_list, "time" = time_list)
optimal_selling.df

Do THis for Optimal Buying time?

ggplot(optimal_selling.df) + geom_histogram(mapping = aes(x= time)) + ggtitle("How Often Best Selling Time is vs. Time From Game")

What time should you look to buy?

price_list = c()
time_list = c()
for (game in 1:nrow(cleaned_worldcupmatches)) {
  price_game_data <- getSpyAndGameDataForOneGame(spydata, cleaned_worldcupmatches, game, 3)
  lowestdatapoint = price_game_data[which.min(price_game_data$average),]
  lowestpriceforgame <- lowestdatapoint$average
  time <- lowestdatapoint$"time.from.game"
  price_list = append(price_list, lowestpriceforgame)
  time_list = append(time_list, time)
}
optimal_buying.df <- data.frame("price" = price_list, "time" = time_list)
ggplot(optimal_buying.df) + geom_histogram(mapping = aes(x= time)) + ggtitle("How Often Best Buying Time is vs. Time From Game")

Another idea we wanted to explore was the optimal buying and selling times for SPY. The optimal buying time would be when the SPY price is the lowest and the optimal selling time would be when the SPY price is the highest. In order to find the optimal times from the game, we found the maximum and minimum price of SPY during each game. From there, we found the corresponding time from game for these maximum and minimum price values. With this data, we created two histograms: one that demonstrates the optimal buying times from a world cup game and another that demonstrated the optimal selling times from a world cup game. The histograms display the time from game on the x-axis and show the amount of hames that have their optimal selling or buying time at that time value. For the optimal selling histogram, there are peaks at 10,000 seconds and 5,000 seconds before the game. These two time values correspond to around three hours before the game and one and a half hours before the game, respectively. There were other outliers in the histogram, but these two values seem to be the best times around a world cup game to sell SPY stock, based on our data. For the optimal buying histogram, there was a large peak around 10,000 seconds before the game, which is three hours before the game. The histogram is skewed right, so the times where the SPY price was the lowest was before the game. From this histogram, it appears that the best time to buy SPY stock is three hours before the start of a world cup game. 



Does the importance of the game matter in the total amount of trades?

allspydata$Stage[grepl("Group", allspydata$Stage, fixed = TRUE)]  = "Group"
ggplot(allspydata, aes(log(volume), Stage, fill = Stage)) + geom_boxplot() + ggtitle("Log(Volume) vs. Stage Of Game")

allspydata$Stage[grepl("Group", allspydata$Stage, fixed = TRUE)]  = "Group"
ggplot(allspydata, aes(log(volume), Stage, fill = Stage)) + geom_boxplot() + ggtitle("Log(Volume) vs. Stage Of Game")
LS0tCnRpdGxlOiAiTUFUSCAzMTggRmluYWwgUHJvamVjdCIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKIyBNQVRIIDMxOCBGaW5hbCBQcm9qZWN0OiBUaGUgRWZmZWN0IG9mIFdvcmxkIEN1cCBvbiBTdG9jayBQcmljZSBhbmQgVHJhZGluZyBBY3Rpdml0eQoKYGBge3J9CmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KGRwbHlyKQpsaWJyYXJ5KE1BU1MpCmxpYnJhcnkobHVicmlkYXRlKQpsaWJyYXJ5KHN0cmluZ3IpCmxpYnJhcnkoR0dhbGx5KQpsaWJyYXJ5KGtuaXRyKQpsaWJyYXJ5KGthYmxlRXh0cmEpCmxpYnJhcnkodGlkeXF1YW50KQpgYGAKCiMgSW50cm9kdWN0aW9uCgpPdXIgZ29hbCBpbiB0aGlzIHByb2plY3Qgd2FzIHRvIGV4cGxvcmUgdGhlIGVmZmVjdCB0aGUgRklGQSBXb3JsZCBDdXAgaGFzIG9uIHRoZSBzdG9jayBtYXJrZXQuIEluIHJlc2VhcmNoaW5nIHRvIHByZXBhcmUsIHdlIGZvdW5kIHRoYXQgdGhlIFdvcmxkIEN1cCBoYXMgYSBnZW5lcmFsbHkgbmVnYXRpdmUgaW1wYWN0IG9uIHRoZSBtYXJrZXQuIEFjY29yZGluZyB0byBhbiBhcnRpY2xlIGZyb20gTWFya2V0V2F0Y2gsIGEgY291bnRyeVwncyBhdmVyYWdlIG1hcmtldCByZXR1cm4gc2lnbmlmaWNhbnRseSBkcm9wcyBhZnRlciB0aGVpciB0ZWFtIGlzIGVsaW1pbmF0ZWQgZnJvbSB0aGUgQ3VwLiBUaGUgaW52ZXJzZSBjYW5cJ3QgYmUgc2FpZCBmb3IgdGVhbSB3aW5zLCB3aGljaCBsZWFkcyB0byB0aGUgb3ZlcmFsbCBtYXJrZXQgZGVjcmVhc2luZy4gT3VyIGludGVyZXN0IHdhcyB0byBpbnZlc3RpZ2F0ZSB0aGUgbWFya2V0IHRyZW5kcywgc3BlY2lmaWNhbGx5IHJlZ2FyZGluZyB0aGUgUyZQIDUwMCwgaW4gcmVsYXRpb24gdG8gdGhlIHRpbWVzIG9mIFdvcmxkIEN1cCBnYW1lcy7CoAoKIyMgRXhwbG9yYXRpb24KCmBgYHtyfQpjYW5kbGVTdGlja19wbG90PC1mdW5jdGlvbihzeW1ib2wsZnJvbSx0byl7CiAgdHFfZ2V0KHN5bWJvbCwKICAgICAgICBmcm9tID0gZnJvbSwKICAgICAgICB0byA9IHRvLAogICAgICAgIHdhcm5pbmdzID0gRkFMU0UpICU+JSBtdXRhdGUoZ3JlZW5SZWQ9aWZlbHNlKG9wZW4tY2xvc2U+MCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIlJlZCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICJHcmVlbiIpKSAlPiUKICAgIGdncGxvdCgpKwogICAgZ2VvbV9zZWdtZW50KGFlcyh4ID0gZGF0ZSwKICAgICAgICAgICAgICAgICAgICAgeGVuZD1kYXRlLAogICAgICAgICAgICAgICAgICAgICB5ID1vcGVuLAogICAgICAgICAgICAgICAgICAgICB5ZW5kID1jbG9zZSwKICAgICAgICAgICAgICAgICAgICAgY29sb3VyPWdyZWVuUmVkKSwKICAgICAgICAgICAgICAgICBzaXplPTMpKwogICAgdGhlbWVfdHEoKSsKICAgIGdlb21fc2VnbWVudChhZXMoeCA9IGRhdGUsCiAgICAgICAgICAgICAgICAgICAgIHhlbmQ9ZGF0ZSwKICAgICAgICAgICAgICAgICAgICAgeSA9aGlnaCwKICAgICAgICAgICAgICAgICAgICAgeWVuZCA9bG93LAogICAgICAgICAgICAgICAgICAgICBjb2xvdXI9Z3JlZW5SZWQpKSsKICAgIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9YygiRm9yZXN0IEdyZWVuIiwiUmVkIikpKwogICAgZ2d0aXRsZShwYXN0ZTAoc3ltYm9sLCIgKCIsZnJvbSwiIC0gIix0bywiKSIpKSsKICAgIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9Im5vbmUiLAogICAgICAgICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgICAgYXhpcy50aXRsZS54PWVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIHZqdXN0ID0gMC41LCBoanVzdD0xKSwKICAgICAgICAgIHBsb3QudGl0bGU9IGVsZW1lbnRfdGV4dChoanVzdD0wLjUpKQp9CgpgYGAKCmBgYHtyfQpjYW5kbGVTdGlja19wbG90KCJTUFkiLCBmcm9tID0gJzIwMDItMDUtMzEnLCB0byA9ICcyMDAyLTA2LTMwJykKY2FuZGxlU3RpY2tfcGxvdCgiU1BZIiwgZnJvbSA9ICcyMDA2LTA2LTA5JywgdG8gPSAnMjAwNi0wNy0wOScpCmNhbmRsZVN0aWNrX3Bsb3QoIlNQWSIsIGZyb20gPSAnMjAxMC0wNi0xMScsdG8gPSAnMjAxMC0wNy0xMScpCmNhbmRsZVN0aWNrX3Bsb3QoIlNQWSIsIGZyb20gPSAnMjAxNC0wNi0xMicsdG8gPSAnMjAxNC0wNy0xMycpCmBgYAoKIyBMb2FkIERhdGEKCmBgYHtyfQpzcHlkYXRhID0gYXNfdGliYmxlKHJlYWQuY3N2KCIxX21pbl9TUFlfMjAwOC0yMDIxLmNzdiIpKQpgYGAKCmBgYHtyfQp3b3JsZGN1cG1hdGNoZXMgPSBhc190aWJibGUocmVhZC5jc3YoIldvcmxkQ3VwTWF0Y2hlcy5jc3YiKSkKYGBgCgpXZSB3ZXJlIGludGVyZXN0ZWQgaW4gbG9va2luZyBhdCB0aGUgZ2VuZXJhbCBwcmljZSBvZiB0aGUgbWFya2V0IGR1cmluZyB0aGUgd29ybGQgY3VwLCB0byBjb25maXJtIGlmIG91ciBkYXRhIHNob3dzIHRoZSBwcm9wb3NlZCB0cmVuZCBvZiBkZWNyZWFzZWQgcHJpY2UgZHVyaW5nIHRoZSBXb3JsZCBDdXDCoCB3ZSBmb3VuZCBpbiBvdXIgcmVzZWFyY2guIFRvIGRvIHRoaXMgd2UgdXNlZCBhIGdyYXBoaW5nIG1ldGhvZCBjYWxsZWQgY2FuZGxlc3RpY2tzIHBsb3RzLiBUaGVzZSBwbG90cyBzaG93IHRoZSBhdmVyYWdlIGFuZCB2YXJpYXRpb24gb2YgdGhlIHByaWNlIG92ZXIgYSBnaXZlbiBtb250aC4gRWFjaCBwbG90IHNwYW5uZWQgdGhlIG1vbnRoIG9mIHRoZSBXb3JsZCBDdXAgZm9yIHRoZSB5ZWFycyAyMDAyLCAyMDA2LCAyMDEwLCAyMDE0LiBCb3RoIHRoZSBncmFwaCBmb3IgMjAwMiBhbmQgMjAxMCBkaXNwbGF5IGEgZ2VuZXJhbGx5IGRlY3JlYXNpbmcgdHJlbmQgdGhyb3VnaG91dCB0aGUgbW9udGguIEhvd2V2ZXIsIHRoZSAyMDA2IGFuZCAyMDE0IGdyYXBocyBpbnN0ZWFkIHNob3cgYSBnZW5lcmFsIGluY3JlYXNlIGluIHByaWNlIG92ZXIgdGltZS4gVG8gYmV0dGVyIHVuZGVyc3RhbmQgdHJlbmRzIGluIHRoZSBkYXRhLCB3ZSB0aGVuIGxvb2tlZCBjbG9zZXIgYXQgaW5mb3JtYXRpb24gZnJvbSBzaW5ndWxhciBnYW1lcy7CoAoKXApcCgojIEhlbHBlciBGdW5jdGlvbnMKCiMjIEdldCBPbmx5IFNweSBEYXRhIGZvciBhIFNwZWNpZmljIEdhbWUKCmBgYHtyfQojQ2xlYW4gU3B5RGF0YSBQZXIgR2FtZQpnZXRTcHlEYXRhV2l0aGluUmFuZ2VvZkdhbWUgPSBmdW5jdGlvbihzcHlkYXRhLGdhbWVfZGF0ZSxyYW5nZSl7CiAgcmFuZ2VJblNlY29uZHMgPSA2MCAqIDYwICogcmFuZ2UKICByZXR1cm4oZmlsdGVyKHNweWRhdGEsIChkYXRlID49IGdhbWVfZGF0ZSAtIHJhbmdlSW5TZWNvbmRzKSAmIChkYXRlIDw9IGdhbWVfZGF0ZSArIHJhbmdlSW5TZWNvbmRzKSkpCn0KYGBgCgojIyBDaGVjayBpZiB0aGVyZSBpcyBTcHkgZGF0YSBmb3IgYSBnYW1lCgpgYGB7cn0KaGFzU3B5RGF0YVdpdGhpblJhbmdlT2ZHYW1lID0gZnVuY3Rpb24oc3B5ZGF0YSwgZ2FtZV9kYXRlcywgcmFuZ2UpewogIGxpc3QgPSBjKCkKICBmb3IoZ2FtZV9kYXRlIGluIDE6bGVuZ3RoKGdhbWVfZGF0ZXMpKXsKICAgIGxpc3QgPSBhcHBlbmQobGlzdCwgbnJvdyhnZXRTcHlEYXRhV2l0aGluUmFuZ2VvZkdhbWUoc3B5ZGF0YSwgZ2FtZV9kYXRlID0gZ2FtZV9kYXRlc1tnYW1lX2RhdGVdLCByYW5nZSkpICE9IDApCiAgfQogIHJldHVybihsaXN0KQp9CmBgYAoKIyMgR2V0IFNweSBEYXRhIGNvbWJpbmVkIHdpdGggR2FtZSBEYXRhIGZvciBhIHNldCBvZiBHYW1lcwoKYGBge3J9CiNDbGVhbiBTcHlkYXRhIFBlciBXb3JsZGN1cCBSZXR1cm5zIGEgc2V0IG9mIHNweWRhdGEgd2l0aCB0aGVpciBjb3JyZXNwb25kaW5nIGdhbWUgZGF0YQpnZXRTcHlBbmRHYW1lRGF0YVdpdGhpbldvcmxkY3VwID0gZnVuY3Rpb24od29ybGRjdXAsIHNweWRhdGEsIHJhbmdlKXsKICB6ID0gZ2V0U3B5RGF0YVdpdGhpblJhbmdlb2ZHYW1lKHNweWRhdGEsIHdvcmxkY3VwW1sxLCJEYXRldGltZSJdXSwgcmFuZ2UpCiAgZ2FtZXJvdyA9IHdvcmxkY3VwWzEsXQogIGZvcihjb2xJbmR4IGluIDE6IG5jb2woZ2FtZXJvdykpewogICAgICBjb2x2YWx1ZSA9IHdvcmxkY3VwW1sxLCBjb2xJbmR4XV0KICAgICAgY29sbmFtZSA9IGNvbG5hbWVzKHdvcmxkY3VwKVtjb2xJbmR4XQogICAgICB6W2NvbG5hbWVdID0gcmVwKGNvbHZhbHVlLCB0aW1lcz0gbnJvdyh6KSkKICB9CiAgelsidGltZS5mcm9tLmdhbWUiXSA9IGFzLm51bWVyaWMoZGlmZnRpbWUoeiRkYXRlLCB3b3JsZGN1cFtbMSwiRGF0ZXRpbWUiXV0sdW5pdHMgPSAic2VjcyIpKQogIGZvcihnYW1lSW5keCBpbiAyOm5yb3cod29ybGRjdXApKXsKICAgeCA9IGdldFNweURhdGFXaXRoaW5SYW5nZW9mR2FtZShzcHlkYXRhLCB3b3JsZGN1cFtbZ2FtZUluZHgsIkRhdGV0aW1lIl1dLCByYW5nZSkKICAgZ2FtZXJvdyA9IHdvcmxkY3VwW2dhbWVJbmR4LF0KICAgZm9yKGNvbEluZHggaW4gMTogbmNvbChnYW1lcm93KSl7CiAgICAgIGNvbHZhbHVlID0gd29ybGRjdXBbW2dhbWVJbmR4LCBjb2xJbmR4XV0KICAgICAgY29sbmFtZSA9IGNvbG5hbWVzKHdvcmxkY3VwKVtjb2xJbmR4XQogICAgICB4W2NvbG5hbWVdID0gcmVwKGNvbHZhbHVlLCB0aW1lcz0gbnJvdyh4KSkKICAgfQogICB4WyJ0aW1lLmZyb20uZ2FtZSJdID0gYXMubnVtZXJpYyhkaWZmdGltZSh4JGRhdGUsIHgkRGF0ZXRpbWUsIHVuaXRzID0gInNlY3MiKSkKICAKICAgeiA9IHVuaW9uX2FsbCh6LHgpCiAgfQogIHJldHVybih6KQp9CmBgYAoKIyMgR2V0IFNweSBEYXRhIGNvbWJpbmVkIHdpdGggR2FtZSBEYXRhIGZvciBhIHNpbmdsZSBnYW1lCgpgYGB7cn0KI0dpdmVzIFNweWRhdGEgYW5kIERpZmZlcmVuY2UgZnJvbSB0aGUgZ2FtZSB0aW1lIGZvciBlYWNoIHdvcmxkY3VwIGdhbWUKZ2V0U3B5QW5kR2FtZURhdGFGb3JPbmVHYW1lID0gZnVuY3Rpb24oc3B5ZGF0YSx3b3JsZGN1cCwgZ2FtZV9pbmRleCwgcmFuZ2UpewogIHogPSBnZXRTcHlEYXRhV2l0aGluUmFuZ2VvZkdhbWUoc3B5ZGF0YSwgd29ybGRjdXBbW2dhbWVfaW5kZXgsIkRhdGV0aW1lIl1dLCByYW5nZSkKICBmb3IoY29sSW5keCBpbiAxOiBuY29sKHdvcmxkY3VwW2dhbWVfaW5kZXgsXSkpewogICAgICBjb2x2YWx1ZSA9IHdvcmxkY3VwW1tnYW1lX2luZGV4LCBjb2xJbmR4XV0KICAgICAgY29sbmFtZSA9IGNvbG5hbWVzKHdvcmxkY3VwKVtjb2xJbmR4XQogICAgICB6W2NvbG5hbWVdID0gcmVwKGNvbHZhbHVlLCB0aW1lcz0gbnJvdyh6KSkKICB9CiAgelsidGltZS5mcm9tLmdhbWUiXSA9IGFzLm51bWVyaWMoZGlmZnRpbWUoeiRkYXRlLCByZXAod29ybGRjdXBbW2dhbWVfaW5kZXgsIkRhdGV0aW1lIl1dLCB0aW1lcyA9IG5yb3coeikpLCB1bml0cz0ic2VjcyIpKQogIHJldHVybih6KQp9CmBgYAoKIyBDbGVhbmluZyBEYXRhCgpgYGB7cn0KI1VwZGF0ZSAKc3B5ZGF0YSRkYXRlID0gYXMuUE9TSVhjdChzcHlkYXRhJGRhdGUsIGZvcm1hdD0iJVklbSVkICVIOiVNOiVTIikKCiNSZW1vdmUgUm93cyBjb250YWluaW5nIE5BJ3MKY2xlYW5lZF93b3JsZGN1cG1hdGNoZXMgPSB1bmlxdWUod29ybGRjdXBtYXRjaGVzWyFhcHBseShpcy5uYSh3b3JsZGN1cG1hdGNoZXMpIHwgd29ybGRjdXBtYXRjaGVzID09ICIiLCAxLCBhbGwpLF0pCgojQ29udmVydCBEYXRlIGFuZCBUaW1lIGludG8gUE9TSVggRURUIApjbGVhbmVkX3dvcmxkY3VwbWF0Y2hlcyREYXRldGltZSA9IGFzLlBPU0lYY3QoY2xlYW5lZF93b3JsZGN1cG1hdGNoZXMkRGF0ZXRpbWUsIGZvcm1hdCA9ICIlZSAlYiAlWSAtICVSIikgLSA2MCAqIDYwCgojRmlsdGVyIEdhbWVzIG9uIHRoZSBXZWVrZW5kCmNsZWFuZWRfd29ybGRjdXBtYXRjaGVzID0gZmlsdGVyKGNsZWFuZWRfd29ybGRjdXBtYXRjaGVzLCB3ZGF5KGFzLkRhdGUoRGF0ZXRpbWUpKSAhPSA3ICYgd2RheShhcy5EYXRlKERhdGV0aW1lKSkgIT0gMSkKCiNGaWx0ZXIgR2FtZXMgdGhhdCBoYXZlIG5vIGNvcnJlc3BvbmRpbmcgRGF0YQpjbGVhbmVkX3dvcmxkY3VwbWF0Y2hlcyA9IGFkZF9jb2x1bW4oY2xlYW5lZF93b3JsZGN1cG1hdGNoZXMsIkhhc1NweURhdGEiID0gaGFzU3B5RGF0YVdpdGhpblJhbmdlT2ZHYW1lKHNweWRhdGEsIGNsZWFuZWRfd29ybGRjdXBtYXRjaGVzJERhdGV0aW1lLCAzKSkKY2xlYW5lZF93b3JsZGN1cG1hdGNoZXMgPSBmaWx0ZXIoY2xlYW5lZF93b3JsZGN1cG1hdGNoZXMsIGNsZWFuZWRfd29ybGRjdXBtYXRjaGVzJEhhc1NweURhdGEgPT0gVFJVRSkKCmNsZWFuZWRfd29ybGRjdXBtYXRjaGVzCmBgYAoKIyMgR2V0IFNweSBEYXRhCgpgYGB7cn0KI0dldCBTcHkgZGF0YSB3aXRoaW4gMyBob3VycyBvZiB0aGUgR2FtZSBGb3IgYm90aCBXb3JsZCBjdXBzCmFsbHNweWRhdGEyMDE0ID0gZ2V0U3B5QW5kR2FtZURhdGFXaXRoaW5Xb3JsZGN1cChmaWx0ZXIoY2xlYW5lZF93b3JsZGN1cG1hdGNoZXMsIFllYXI9PTIwMTQpLCBzcHlkYXRhLCAzKQoKYWxsc3B5ZGF0YTIwMTAgPSBnZXRTcHlBbmRHYW1lRGF0YVdpdGhpbldvcmxkY3VwKGZpbHRlcihjbGVhbmVkX3dvcmxkY3VwbWF0Y2hlcywgWWVhcj09MjAxMCksIHNweWRhdGEsIDMpCgpgYGAKCiMjIE5vcm1hbGl6aW5nIHRoZSBhdmVyYWdlIHByaWNlCgpgYGB7cn0KI05vcm1hbGl6ZSB0aGUgRGF0YSBzbyB0aGF0IHdlIGNhbiBjb21wYXJlIGZhaXJseSB0aGUgZ3Jvd3RoIG9mIHN0b2NrIHByaWNlCm1heC4yMDE0ID0gbWF4KGFsbHNweWRhdGEyMDE0JGF2ZXJhZ2UpCm1heC4yMDEwID0gbWF4KGFsbHNweWRhdGEyMDEwJGF2ZXJhZ2UpCgoKbWluLjIwMTQgPSBtaW4oYWxsc3B5ZGF0YTIwMTQkYXZlcmFnZSkKbWluLjIwMTAgPSBtaW4oYWxsc3B5ZGF0YTIwMTAkYXZlcmFnZSkKCmRpZmZlcmVuY2UuMjAxNCA9IChtYXguMjAxNCkgLSAobWluLjIwMTQpCmRpZmZlcmVuY2UuMjAxMCA9IChtYXguMjAxMCkgLSAobWluLjIwMTApCm5vcm1hbGl6ZWQyMDE0YXZlcmFnZSA9IChhbGxzcHlkYXRhMjAxNCRhdmVyYWdlLW1pbi4yMDE0KS9kaWZmZXJlbmNlLjIwMTQKbm9ybWFsaXplZDIwMTBhdmVyYWdlID0gKGFsbHNweWRhdGEyMDEwJGF2ZXJhZ2UtbWluLjIwMTApL2RpZmZlcmVuY2UuMjAxMAoKCmFsbHNweWRhdGEyMDE0ID0gYWRkX2NvbHVtbihhbGxzcHlkYXRhMjAxNCwgIm5vcm1hbGl6ZWQuYXZlcmFnZSIgPSBub3JtYWxpemVkMjAxNGF2ZXJhZ2UpCmFsbHNweWRhdGEyMDEwID0gYWRkX2NvbHVtbihhbGxzcHlkYXRhMjAxMCwgIm5vcm1hbGl6ZWQuYXZlcmFnZSIgPSBub3JtYWxpemVkMjAxMGF2ZXJhZ2UpCgphbGxzcHlkYXRhID0gdW5pb25fYWxsKGFsbHNweWRhdGEyMDE0LCBhbGxzcHlkYXRhMjAxMCkKCmFsbHNweWRhdGEKYGBgCgpCZWZvcmUgd2UgY291bGQgcGVyZm9ybSBhbnkgdGVzdHMgb24gdGhlIGRhdGEgc2V0cywgd2UgZmlyc3QgaGFkIHRvIHRha2UgaW50byBhY2NvdW50IHRoZSBzdG9jayBwcmljZSBkaWZmZXJlbmNlcyBiZXR3ZWVuIHRoZSB5ZWFycyAyMDEwIGFuZCAyMDE0LiBJbiBvcmRlciB0byBub3JtYWxpemUgdGhlIHN0b2NrIHByaWNlIGRhdGEsIHdlIGhhZCB0byBzcGxpdCB0aGUgZGF0YSBpbnRvIGVhY2ggeWVhciBhbmQgbm9ybWFsaXplIHRoZSBwcmljZXMgd2l0aGluIHRoYXQgeWVhci4gVGhlIG1ldGhvZCB3ZSBjaG9zZSB0byBub3JtYWxpemUgdGhlIHByaWNlcyB3YXMgc3VidHJhY3RpbmcgdGhlIG1pbmltdW0gcHJpY2UgZm9yIHRoYXQgeWVhciBmcm9tIGVhY2ggcHJpY2UuIFRoaXMgdmFsdWUgd2FzIHRoZW4gZGl2aWRlZCBieSB0aGUgZGlmZmVyZW5jZSBiZXR3ZWVuIHRoZSBtYXhpbXVtIGFuZCBtaW5pbXVtIHByaWNlIGZvciB0aGF0IHllYXIuIEVhY2ggbm9ybWFsaXplZCBwcmljZSBpcyBhIHZhbHVlIGJldHdlZW4gemVybyBhbmQgb25lLiBXaGVuIGludGVycHJldGluZyB0aGVzZSB2YWx1ZXMsIHRoZSBjbG9zZXIgdGhlIG5vcm1hbGl6ZWQgdmFsdWUgaXMgdG8gb25lLCB0aGUgY2xvc2VyIHRoZSBwcmljZSBpcyB0byB0aGUgbWF4aW11bSBmb3IgdGhhdCB5ZWFyLiBTaW1pbGFybHksIHRoZSBjbG9zZXIgdGhlIHZhbHVlIGlzIHRvIHplcm8sIHRoZSBjbG9zZXIgdGhlIHByaWNlIGlzIHRvIHRoZSBtaW5pbXVtIGZvciB0aGF0IHllYXIuIEJ5IG5vcm1hbGl6aW5nIHRoZSBwcmljZXMgZm9yIGVhY2ggeWVhciwgd2UgY3JlYXRlZCBhbiBldmVuIHBsYXlpbmcgZmllbGQgZm9yIHByaWNlIGRhdGEsIGFzIHRoZXkgYXJlIGFsbCByZWxhdGl2ZSB0byB0aGUgc3RvY2sgbWFya2V0IGNsaW1hdGUgaW4gdGhlaXIgZ2l2ZW4geWVhci4KCiMgRXhwbG9yaW5nIHRoZSBSZWxhdGlvbnNoaXAgb2YgVGltZSBhbmQgVm9sdW1lCgpMZXQgdXMgZXhwbG9yZSB0aGUgQ29ycmVsYXRpb24gYmV0d2VlbiB0aGUgVGltZSBmb3JtIGdhbWUgYW5kIHRoZSBQcmljZSBvZiB0aGUgc3RvY2sKCiMjIENvcnJlbGF0aW9ucwoKYGBge3J9CmdncGFpcnMoYWxsc3B5ZGF0YSwgY29sdW1ucyA9IGMoInRpbWUuZnJvbS5nYW1lIiwgImF2ZXJhZ2UiLCAidm9sdW1lIiwgIm5vcm1hbGl6ZWQuYXZlcmFnZSIpKQpgYGAKCmBgYHtyfQprYWJsZShjb3IoYWxsc3B5ZGF0YVssIGMoNyw5LDMxLDMyKV0pKQpgYGAKCkFmdGVyIGNsZWFuaW5nIHRoZSBkYXRhIHNldCwgd2UgY29tcHV0ZWQgdGhlIGNyb3NzLWNvcnJlbGF0aW9ucyBmb3IgdGhlIHZhcmlhYmxlczogdGltZSBmcm9tIHRoZSBnYW1lLCB2b2x1bWUgb2YgdHJhZGVzLCBhdmVyYWdlIHByaWNlLCBhbmQgbm9ybWFsaXplZCBhdmVyYWdlIHByaWNlLiBXZSB3ZXJlIG1vc3QgaW50ZXJlc3RlZCBpbiBzZWVpbmcgaG93IHRpbWUgZnJvbSBnYW1lIGFmZmVjdGVkIHZvbHVtZSBvZiB0cmFkZXMgc2luY2Ugdm9sdW1lIHNob3dzIHN0b2NrIHByb2R1Y3Rpdml0eS4gV2UgZm91bmQgdGhhdCB0aW1lIGZyb20gZ2FtZSBoYWQgdGhlIGhpZ2hlc3QgY29ycmVsYXRpb24gd2l0aCBhdmVyYWdlIHByaWNlLCB0aGUgY29ycmVsYXRpb24gd2FzIDAuMjE1LiBXZSBhbHNvIGZvdW5kIHRoYXQgdGhlIGNvcnJlbGF0aW9uIGJldHdlZW4gdGltZSBmcm9tIGdhbWUgYW5kIHZvbHVtZSB3YXMgLjAzMy4gVGhlc2UgbG93IHZhbHVlcyBtYWtlIHNlbnNlIGdpdmVuIHRoZSBkYXRhIHdlIGhhZCBhY2Nlc3MgdG8uIFdlIGRpZCBub3QgaGF2ZSBkYXRhIGZvciBjb21tb25seSB0cmFkZWQgc3RvY2tzIGJ5IGRheSB0cmFkZXJzLiBOZXZlcnRoZWxlc3MsIHdlIHdhbnRlZCB0byByZWdyZXNzIHdpdGggdm9sdW1lIGFzIHRoZSBkZXBlbmRlbnQgdmFyaWFibGUgYW5kIHRpbWUgZnJvbSBnYW1lIGFzIHRoZSBpbmRlcGVuZGVudCB2YXJpYWJsZS4gQWZ0ZXIgYXR0ZW1wdGluZyBtdWx0aXBsZSByZWdyZXNzaW9uIHR5cGVzLCBub25saW5lYXIgcmVncmVzc2lvbiBnYXZlIHVzIHRoZSBiZXN0IGZpdC7CoAoKIyMgTGluZWFyIFJlZ3Jlc3Npb24KCmBgYHtyfQpnZ3Bsb3QoYWxsc3B5ZGF0YSkgKyBnZW9tX3BvaW50KGFlcyh0aW1lLmZyb20uZ2FtZSxub3JtYWxpemVkLmF2ZXJhZ2UpKQpgYGAKCmBgYHtyfQpnZ3Bsb3QoYWxsc3B5ZGF0YSwgYWVzKHRpbWUuZnJvbS5nYW1lLGxvZyh2b2x1bWUpKSkgKyBnZW9tX3BvaW50KCkgKyBnZW9tX3Ntb290aCgpICsgZ2VvbV92bGluZSh4aW50ZXJjZXB0PSAwLCBjb2xvciA9ICJyZWQiKSArIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IDU0MDAsIGNvbG9yID0icmVkIikKCmBgYAoKVGhlIG1vZGVsIHdlIHVzZWQgZm9yIG5vbmxpbmVhciByZWdyZXNzaW9uIGlzIGEgR2VuZXJhbGl6ZWQgQWRkaXRpdmUgTW9kZWwsIGFsc28ga25vd24gYXMgYSBHQU0uIEEgR0FNIGlzIG1hZGUgdXAgb2Ygc3BsaW5lcywgc3BsaW5lcyBhcmUgc21vb3RoIHBvbHlub21pYWwgZnVuY3Rpb25zIHRoYXQgY292ZXIgYSBzbWFsbCByYW5nZS4gVGhlc2Ugc3BsaW5lcyByZXBsYWNlIHRoZSBiZXRhIGNvZWZmaWNpZW50cyB0aGF0IHdlIG5vcm1hbGx5IHNlZSBpbiBsaW5lYXIgcmVncmVzc2lvbiwgc28gdGhhdCB3ZSBjYW4gcmVncmVzcyBvbiBub25saW5lYXIgZGF0YS4gV2hlbiB3ZSBncmFwaCBvdXIgbm9ubGluZWFyIG1vZGVsIG92ZXIgdGhlIHZvbHVtZSBkYXRhLCB3ZSBzZWUgdGhhdCB0aGVyZSBpcyBhIHNwaWtlIGluIHZvbHVtZSBvZiB0cmFkZXMgNTAwMCBzZWNvbmRzIGJlZm9yZSB0aGUgdGltZSBvZiB0aGUgZ2FtZSwgd2hpY2ggaXMgYWJvdXQgYW4gaG91ciBhbmQgYSBoYWxmIGJlZm9yZSB0aGUgZ2FtZS4gQWZ0ZXIgdGhpcyBzcGlrZSwgdGhlcmUgaXMgYSBncmFkdWFsIGluY3JlYXNlIG9uY2UgdGhlIGdhbWUgc3RhcnRzIGFuZCB0aGUgcG9zaXRpdmUgdHJlbmQgY29udGludWVzIGFzIHRoZSBnYW1lIGZpbmlzaGVzLgoKXApcCgojIFNhbXBsZSBHYW1lcyBmcm9tIGEgV29ybGQgQ3VwCgpgYGB7cn0Kc2V0LnNlZWQoMTAwKSAKc2FtcGxlc2l6ZSA9IDEwCndvcmxkY3VwbWF0Y2hlczIwMTQgPSBmaWx0ZXIoY2xlYW5lZF93b3JsZGN1cG1hdGNoZXMsIFllYXIgPT0gMjAxNCkKc2FtcGxld29ybGRjdXBnYW1lcyA9IHNhbXBsZV9uKHdvcmxkY3VwbWF0Y2hlczIwMTQsc2l6ZSA9IHNhbXBsZXNpemUpCmBgYAoKYGBge3J9CmdhbWUxIDwtIGdldFNweUFuZEdhbWVEYXRhRm9yT25lR2FtZShzcHlkYXRhLCBzYW1wbGV3b3JsZGN1cGdhbWVzLCAxLCAzKQp2b2x1bWVzcDEgPC0gZ2dwbG90KGdhbWUxLCBtYXBwaW5nID0gYWVzKHg9ZGF0ZSwgeT1sb2codm9sdW1lKSkpICsgZ2VvbV9wb2ludChhZXMoY29sb3IgPWF2ZXJhZ2UpKSArIGdlb21fdmxpbmUoeGludGVyY2VwdD0gc2FtcGxld29ybGRjdXBnYW1lcyREYXRldGltZVsxXSkgKyBnZ3RpdGxlKCJWb2x1bWUgb3ZlciBUaW1lLCBTYW1wbGUgR2FtZSAxIikKdm9sdW1lc3AxCmBgYAoKYGBge3J9CmdhbWUyIDwtIGdldFNweUFuZEdhbWVEYXRhRm9yT25lR2FtZShzcHlkYXRhLCBzYW1wbGV3b3JsZGN1cGdhbWVzLCAyLCAzKQp2b2x1bWVzcDIgPC0gZ2dwbG90KGdhbWUyLCBtYXBwaW5nID0gYWVzKHg9ZGF0ZSwgeT1sb2codm9sdW1lKSkpICsgZ2VvbV9wb2ludChhZXMoY29sb3IgPWF2ZXJhZ2UpKSArIGdlb21fdmxpbmUoeGludGVyY2VwdD0gc2FtcGxld29ybGRjdXBnYW1lcyREYXRldGltZVsyXSkrIGdndGl0bGUoIlZvbHVtZSBvdmVyIFRpbWUsIFNhbXBsZSBHYW1lIDIiKQp2b2x1bWVzcDIKI0VSUk9SIEFHQUlOIFdFIERPTlQgSEFWRSBGVUxMIERBVEEgRk9SIFRISVMgR0FNRQpgYGAKCmBgYHtyfQpnYW1lMyA8LSBnZXRTcHlBbmRHYW1lRGF0YUZvck9uZUdhbWUoc3B5ZGF0YSwgc2FtcGxld29ybGRjdXBnYW1lcywgMywgMykKdm9sdW1lc3AzIDwtIGdncGxvdChnYW1lMywgbWFwcGluZyA9IGFlcyh4PWRhdGUsIHk9bG9nKHZvbHVtZSkpKSArIGdlb21fcG9pbnQoYWVzKGNvbG9yID1hdmVyYWdlKSkgKyBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQ9IHNhbXBsZXdvcmxkY3VwZ2FtZXMkRGF0ZXRpbWVbM10pKyBnZ3RpdGxlKCJWb2x1bWUgb3ZlciBUaW1lLCBTYW1wbGUgR2FtZSAzIikKdm9sdW1lc3AzCmBgYAoKYGBge3J9CmdhbWU0IDwtIGdldFNweUFuZEdhbWVEYXRhRm9yT25lR2FtZShzcHlkYXRhLCBzYW1wbGV3b3JsZGN1cGdhbWVzLCA0LCAzKQp2b2x1bWVzcDQgPC0gZ2dwbG90KGdhbWU0LCBtYXBwaW5nID0gYWVzKHg9ZGF0ZSwgeT1sb2codm9sdW1lKSkpICsgZ2VvbV9wb2ludChhZXMoY29sb3IgPWF2ZXJhZ2UpKSArIGdlb21fdmxpbmUoeGludGVyY2VwdD0gc2FtcGxld29ybGRjdXBnYW1lcyREYXRldGltZVs0XSkrIGdndGl0bGUoIlZvbHVtZSBvdmVyIFRpbWUsIFNhbXBsZSBHYW1lIDQiKQp2b2x1bWVzcDQKYGBgCgpgYGB7cn0KZ2FtZTUgPC0gZ2V0U3B5QW5kR2FtZURhdGFGb3JPbmVHYW1lKHNweWRhdGEsIHNhbXBsZXdvcmxkY3VwZ2FtZXMsIDUsIDMpCnZvbHVtZXNwNSA8LSBnZ3Bsb3QoZ2FtZTUsIG1hcHBpbmcgPSBhZXMoeD1kYXRlLCB5PWxvZyh2b2x1bWUpKSkgKyBnZW9tX3BvaW50KGFlcyhjb2xvciA9YXZlcmFnZSkpICsgZ2VvbV92bGluZSh4aW50ZXJjZXB0PSBzYW1wbGV3b3JsZGN1cGdhbWVzJERhdGV0aW1lWzVdKSsgZ2d0aXRsZSgiVm9sdW1lIG92ZXIgVGltZSwgU2FtcGxlIEdhbWUgNSIpCnZvbHVtZXNwNQpgYGAKCiMjIFByaWNlIFNjYXR0ZXIgUGxvdHMKClVzaW5nIGF2ZXJhZ2UgcHJpY2UKCmBgYHtyfQpwcmljZXNwMSA8LSBnZ3Bsb3QoZ2FtZTEpICsgZ2VvbV9wb2ludChtYXBwaW5nID0gYWVzKHg9ZGF0ZSwgeT1hdmVyYWdlKSwgY29sb3IgPSJyZWQiKSArIGdlb21fdmxpbmUoeGludGVyY2VwdD0gc2FtcGxld29ybGRjdXBnYW1lcyREYXRldGltZVsxXSkrIGdndGl0bGUoIlByaWNlIG92ZXIgVGltZSwgU2FtcGxlIEdhbWUgMSIpCnByaWNlc3AxCmBgYAoKYGBge3J9CnByaWNlc3AyIDwtIGdncGxvdChnYW1lMikgKyBnZW9tX3BvaW50KG1hcHBpbmcgPSBhZXMoeD1kYXRlLCB5PWF2ZXJhZ2UpLCBjb2xvciA9InJlZCIpICsgZ2VvbV92bGluZSh4aW50ZXJjZXB0PSBzYW1wbGV3b3JsZGN1cGdhbWVzJERhdGV0aW1lWzJdKSsgZ2d0aXRsZSgiUHJpY2Ugb3ZlciBUaW1lLCBTYW1wbGUgR2FtZSAyIikKcHJpY2VzcDIKI0lTU1VFIEJFQ0FVU0UgV0UgRE9OVCBIQVZFIERBVEEgRk9SIDE2OjAwIGFuZCB0aGF0IGlzIHRpbWUgb2YgdGhlIGdhbWUKYGBgCgpgYGB7cn0KcHJpY2VzcDMgPC0gZ2dwbG90KGdhbWUzKSArIGdlb21fcG9pbnQobWFwcGluZyA9IGFlcyh4PWRhdGUsIHk9YXZlcmFnZSksIGNvbG9yID0icmVkIikgKyBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQ9IHNhbXBsZXdvcmxkY3VwZ2FtZXMkRGF0ZXRpbWVbM10pKyBnZ3RpdGxlKCJQcmljZSBvdmVyIFRpbWUsIFNhbXBsZSBHYW1lIDMiKQpwcmljZXNwMwpgYGAKCmBgYHtyfQpwcmljZXNwNCA8LSBnZ3Bsb3QoZ2FtZTQpICsgZ2VvbV9wb2ludChtYXBwaW5nID0gYWVzKHg9ZGF0ZSwgeT1hdmVyYWdlKSwgY29sb3IgPSJyZWQiKSArIGdlb21fdmxpbmUoeGludGVyY2VwdD0gc2FtcGxld29ybGRjdXBnYW1lcyREYXRldGltZVs0XSkrIGdndGl0bGUoIlByaWNlIG92ZXIgVGltZSwgU2FtcGxlIEdhbWUgNCIpCnByaWNlc3A0CmBgYAoKYGBge3J9CnByaWNlc3A1IDwtIGdncGxvdChnYW1lNSwgYWVzKGRhdGUpKSArIGdlb21fcG9pbnQoYWVzKHk9YXZlcmFnZSwgKSwgY29sb3IgPSJyZWQiKSArIGdlb21fdmxpbmUoeGludGVyY2VwdD0gc2FtcGxld29ybGRjdXBnYW1lcyREYXRldGltZVs1XSkrIGdndGl0bGUoIlByaWNlIG92ZXIgVGltZSwgU2FtcGxlIEdhbWUgNSIpCnByaWNlc3A1CmBgYAoKV2UgbmV4dCBsb29rZWQgYXQgdGhlIHZvbHVtZSBvZiB0cmFkaW5nIG92ZXIgYSByYW5nZSBvZiB0aW1lIGZyb20gZml2ZSBzYW1wbGUgZ2FtZXMuIFVzaW5nIGdncG9pbnQsIHdlIHBsb3R0ZWQgdGhlIHNjYXR0ZXIgcGxvdCBvZiB0aGUgbWFya2V0IHZvbHVtZSBvdmVyIGEgcGVyaW9kIG9mIGEgZmV3IGhvdXJzIGJlZm9yZSBhbmQgYWZ0ZXIgdGhlIHN0YXJ0IG9mIHRoZSBnYW1lLCBhbmQgd2UgaW5kaWNhdGVkIHRoZSBzdGFydCB0aW1lIHdpdGggYSB2ZXJ0aWNhbCBsaW5lIG9uIHRoZSBncmFwaC4gVGhlIHZhbHVlcyBmb3Igdm9sdW1lIGFyZSB2ZXJ5IGxhcmdlIGFuZCB2YXJpZWQsIHdoaWNoIG1ha2VzIHRoZSBncmFwaHMgZGlmZmljdWx0IHRvIHJlYWQuIFRvIG1ha2UgdGhlbSBtb3JlIGRpZ2VzdGlibGUsIHdlIGluc3RlYWQgdXNlZCB0aGUgbG9nIG9mIHZvbHVtZSBhcyB0aGUgZGVwZW5kZW50IHZhcmlhYmxlLCBnaXZpbmcgdXMgc21hbGxlciBudW1iZXJzLiBXZSBmb3VuZCB0aGF0LCBpbiBnZW5lcmFsLCB0aGVyZSBpcyBhIHNsaWdodCBkaXAgaW4gdGhlIHZvbHVtZSBhcm91bmQgdGhlIHN0YXJ0IHRpbWUgb2YgdGhlIGdhbWUuIFRoaXMgYWdyZWVzIHdpdGggZmluZGluZ3MgZnJvbSBvdXIgcmVzZWFyY2ggdGhhdCBzdG9jayBtYXJrZXQgYWN0aXZpdHkgZHJvcHMgZHVycmluZyB0aGUgV29ybGQgQ3VwIGFzIG1vcmUgYXR0ZW50aW9uIGlzIGRpcmVjdGVkIHRvd2FyZHMgdGhlIGdhbWVzLiBXZSBhbHNvIHVzZWQgc2NhdHRlciBwbG90cyB0byBsb29rIGF0IHRoZSBhdmVyYWdlIHByaWNlIG9mIHN0b2NrcyBvdmVyIGEgcmFuZ2Ugb2YgdGltZSBhcm91bmQgdGhlIHN0YXJ0IHRpbWUgb2Ygc2FtcGxlIGdhbWVzLiBBcyBmb3IgdGhlIHZvbHVtZSBwbG90cywgd2UgaW5kaWNhdGVkIHRoZSBzdGFydCB0aW1lIG9mIHRoZSBnYW1lIHdpdGggYSB2ZXJ0aWNhbCBsaW5lIG9uIHRoZSBncmFwaC4gVGhlIGZpZ3VyZXMgc2hvdyB0aGF0IHRoZSBhdmVyYWdlIHByaWNlIHRlbmRzIHRvIGRyb3AganVzdCBiZWZvcmUgdGhlIHN0YXJ0IG9mIHRoZSBnYW1lLCBhbmQgdGhlbiBpbmNyZWFzZS4gVGhlc2UgdHJlbmRzIGluIHByaWNlIGxlYWQgdXMgdG8gZXhwbG9yZSB0aGUgdGltZXMgaXQgd291bGQgYmUgYmVzdCB0byBib3RoIGJ1eSBhbmQgc2VsbCBzdG9ja3MuCgpcClwKCiMjIEp1c3QgVVNBIEdhbWVzCgpgYGB7cn0Kd29ybGRjdXBtYXRjaGVzVVNBaG9tZSA9IGZpbHRlcihjbGVhbmVkX3dvcmxkY3VwbWF0Y2hlcywgSG9tZS5UZWFtLk5hbWUgPT0gIlVTQSIpCndvcmxkY3VwbWF0Y2hlc1VTQWF3YXkgPSBmaWx0ZXIoY2xlYW5lZF93b3JsZGN1cG1hdGNoZXMsIEF3YXkuVGVhbS5OYW1lID09ICJVU0EiKQp3b3JsZGN1cG1hdGNoZXNVU0EgPC0gdW5pb25fYWxsKHdvcmxkY3VwbWF0Y2hlc1VTQWF3YXksd29ybGRjdXBtYXRjaGVzVVNBaG9tZSkKd29ybGRjdXBtYXRjaGVzVVNBCmBgYAoKYGBge3J9CmdhbWUxVVNBIDwtIGdldFNweUFuZEdhbWVEYXRhRm9yT25lR2FtZShzcHlkYXRhLCB3b3JsZGN1cG1hdGNoZXNVU0EsIDEsIDMpCnZvbHVtZXNwMVVTQSA8LSBnZ3Bsb3QoZ2FtZTFVU0EpICsgZ2VvbV9wb2ludChtYXBwaW5nID0gYWVzKHg9ZGF0ZSwgeT1sb2codm9sdW1lKSksIGNvbG9yID0icmVkIikgKyBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQ9IHdvcmxkY3VwbWF0Y2hlc1VTQSREYXRldGltZVsxXSkrIGdndGl0bGUoIlZvbHVtZSBvdmVyIFRpbWUsIFVTQSBHYW1lIDEsIDIwMTAiKQp2b2x1bWVzcDFVU0EKYGBgCgpgYGB7cn0KZ2FtZTJVU0EgPC0gZ2V0U3B5QW5kR2FtZURhdGFGb3JPbmVHYW1lKHNweWRhdGEsIHdvcmxkY3VwbWF0Y2hlc1VTQSwgMiwgMykKdm9sdW1lc3AyVVNBIDwtIGdncGxvdChnYW1lMlVTQSkgKyBnZW9tX3BvaW50KG1hcHBpbmcgPSBhZXMoeD1kYXRlLCB5PWxvZyh2b2x1bWUpKSwgY29sb3IgPSJyZWQiKSArIGdlb21fdmxpbmUoeGludGVyY2VwdD0gd29ybGRjdXBtYXRjaGVzVVNBJERhdGV0aW1lWzJdKSsgZ2d0aXRsZSgiVm9sdW1lIG92ZXIgVGltZSwgVVNBIEdhbWUgMiwgMjAxNCIpCnZvbHVtZXNwMlVTQQpgYGAKCmBgYHtyfQpnYW1lM1VTQSA8LSBnZXRTcHlBbmRHYW1lRGF0YUZvck9uZUdhbWUoc3B5ZGF0YSwgd29ybGRjdXBtYXRjaGVzVVNBLCAzLCAzKQp2b2x1bWVzcDNVU0EgPC0gZ2dwbG90KGdhbWUzVVNBKSArIGdlb21fcG9pbnQobWFwcGluZyA9IGFlcyh4PWRhdGUsIHk9dm9sdW1lKSwgY29sb3IgPSJyZWQiKSArIGdlb21fdmxpbmUoeGludGVyY2VwdD0gd29ybGRjdXBtYXRjaGVzVVNBJERhdGV0aW1lWzNdKSsgZ2d0aXRsZSgiVm9sdW1lIG92ZXIgVGltZSwgVVNBIEdhbWUgMiwgMjAxMCIpCnZvbHVtZXNwM1VTQQpgYGAKCmBgYHtyfQpnYW1lNFVTQSA8LSBnZXRTcHlBbmRHYW1lRGF0YUZvck9uZUdhbWUoc3B5ZGF0YSwgd29ybGRjdXBtYXRjaGVzVVNBLCA0LCAzKQp2b2x1bWVzcDRVU0EgPC0gZ2dwbG90KGdhbWU0VVNBKSArIGdlb21fcG9pbnQobWFwcGluZyA9IGFlcyh4PWRhdGUsIHk9dm9sdW1lKSwgY29sb3IgPSJyZWQiKSArIGdlb21fdmxpbmUoeGludGVyY2VwdD0gd29ybGRjdXBtYXRjaGVzVVNBJERhdGV0aW1lWzRdKSsgZ2d0aXRsZSgiVm9sdW1lIG92ZXIgVGltZSwgVVNBIEdhbWUgMSwgMjAxNCIpCnZvbHVtZXNwNFVTQQpgYGAKCmBgYHtyfQpwcmljZXNwNFVTQSA8LSBnZ3Bsb3QoZ2FtZTRVU0EpICsgZ2VvbV9wb2ludChtYXBwaW5nID0gYWVzKHg9ZGF0ZSwgeT1hdmVyYWdlKSwgY29sb3IgPSJyZWQiKSArIGdlb21fdmxpbmUoeGludGVyY2VwdD0gd29ybGRjdXBtYXRjaGVzVVNBJERhdGV0aW1lWzRdKSsgZ2d0aXRsZSgiUHJpY2Ugb3ZlciBUaW1lLCBVU0EgR2FtZSAxLCAyMDE0IikKcHJpY2VzcDRVU0EKYGBgCgojIElzIHRoZXJlIGEgd2F5IHRvIG1ha2UgbW9uZXkgZHVyaW5nIFdvcmxkIEN1cCBHYW1lcz8KCiMgV2hhdCB0aW1lIHNob3VsZCB5b3UgbG9vayB0byBzZWxsPwoKYGBge3J9CnByaWNlX2xpc3QgPSBjKCkKdGltZV9saXN0ID0gYygpCmZvciAoZ2FtZSBpbiAxOm5yb3coY2xlYW5lZF93b3JsZGN1cG1hdGNoZXMpKSB7CiAgcHJpY2VfZ2FtZV9kYXRhIDwtIGdldFNweUFuZEdhbWVEYXRhRm9yT25lR2FtZShzcHlkYXRhLCBjbGVhbmVkX3dvcmxkY3VwbWF0Y2hlcywgZ2FtZSwgMykKICBoaWdoZXN0ZGF0YXBvaW50ID0gcHJpY2VfZ2FtZV9kYXRhW3doaWNoLm1heChwcmljZV9nYW1lX2RhdGEkYXZlcmFnZSksXQogIGhpZ2hlc3RwcmljZWZvcmdhbWUgPC0gaGlnaGVzdGRhdGFwb2ludCRhdmVyYWdlCiAgdGltZSA8LSBoaWdoZXN0ZGF0YXBvaW50JCJ0aW1lLmZyb20uZ2FtZSIKICBwcmljZV9saXN0ID0gYXBwZW5kKHByaWNlX2xpc3QsIGhpZ2hlc3RwcmljZWZvcmdhbWUpCiAgdGltZV9saXN0ID0gYXBwZW5kKHRpbWVfbGlzdCwgdGltZSkKfQpgYGAKCmBgYHtyfQpvcHRpbWFsX3NlbGxpbmcuZGYgPC0gZGF0YS5mcmFtZSgicHJpY2UiID0gcHJpY2VfbGlzdCwgInRpbWUiID0gdGltZV9saXN0KQpvcHRpbWFsX3NlbGxpbmcuZGYKYGBgCgpEbyBUSGlzIGZvciBPcHRpbWFsIEJ1eWluZyB0aW1lPwoKYGBge3J9CmdncGxvdChvcHRpbWFsX3NlbGxpbmcuZGYpICsgZ2VvbV9oaXN0b2dyYW0obWFwcGluZyA9IGFlcyh4PSB0aW1lKSkgKyBnZ3RpdGxlKCJIb3cgT2Z0ZW4gQmVzdCBTZWxsaW5nIFRpbWUgaXMgdnMuIFRpbWUgRnJvbSBHYW1lIikKYGBgCgojIFdoYXQgdGltZSBzaG91bGQgeW91IGxvb2sgdG8gYnV5PwoKYGBge3J9CnByaWNlX2xpc3QgPSBjKCkKdGltZV9saXN0ID0gYygpCmZvciAoZ2FtZSBpbiAxOm5yb3coY2xlYW5lZF93b3JsZGN1cG1hdGNoZXMpKSB7CiAgcHJpY2VfZ2FtZV9kYXRhIDwtIGdldFNweUFuZEdhbWVEYXRhRm9yT25lR2FtZShzcHlkYXRhLCBjbGVhbmVkX3dvcmxkY3VwbWF0Y2hlcywgZ2FtZSwgMykKICBsb3dlc3RkYXRhcG9pbnQgPSBwcmljZV9nYW1lX2RhdGFbd2hpY2gubWluKHByaWNlX2dhbWVfZGF0YSRhdmVyYWdlKSxdCiAgbG93ZXN0cHJpY2Vmb3JnYW1lIDwtIGxvd2VzdGRhdGFwb2ludCRhdmVyYWdlCiAgdGltZSA8LSBsb3dlc3RkYXRhcG9pbnQkInRpbWUuZnJvbS5nYW1lIgogIHByaWNlX2xpc3QgPSBhcHBlbmQocHJpY2VfbGlzdCwgbG93ZXN0cHJpY2Vmb3JnYW1lKQogIHRpbWVfbGlzdCA9IGFwcGVuZCh0aW1lX2xpc3QsIHRpbWUpCn0KYGBgCgpgYGB7cn0Kb3B0aW1hbF9idXlpbmcuZGYgPC0gZGF0YS5mcmFtZSgicHJpY2UiID0gcHJpY2VfbGlzdCwgInRpbWUiID0gdGltZV9saXN0KQpnZ3Bsb3Qob3B0aW1hbF9idXlpbmcuZGYpICsgZ2VvbV9oaXN0b2dyYW0obWFwcGluZyA9IGFlcyh4PSB0aW1lKSkgKyBnZ3RpdGxlKCJIb3cgT2Z0ZW4gQmVzdCBCdXlpbmcgVGltZSBpcyB2cy4gVGltZSBGcm9tIEdhbWUiKQpgYGAKCkFub3RoZXIgaWRlYSB3ZSB3YW50ZWQgdG8gZXhwbG9yZSB3YXMgdGhlIG9wdGltYWwgYnV5aW5nIGFuZCBzZWxsaW5nIHRpbWVzIGZvciBTUFkuIFRoZSBvcHRpbWFsIGJ1eWluZyB0aW1lIHdvdWxkIGJlIHdoZW4gdGhlIFNQWSBwcmljZSBpcyB0aGUgbG93ZXN0IGFuZCB0aGUgb3B0aW1hbCBzZWxsaW5nIHRpbWUgd291bGQgYmUgd2hlbiB0aGUgU1BZIHByaWNlIGlzIHRoZSBoaWdoZXN0LiBJbiBvcmRlciB0byBmaW5kIHRoZSBvcHRpbWFsIHRpbWVzIGZyb20gdGhlIGdhbWUsIHdlIGZvdW5kIHRoZSBtYXhpbXVtIGFuZCBtaW5pbXVtIHByaWNlIG9mIFNQWSBkdXJpbmcgZWFjaCBnYW1lLiBGcm9tIHRoZXJlLCB3ZSBmb3VuZCB0aGUgY29ycmVzcG9uZGluZyB0aW1lIGZyb20gZ2FtZSBmb3IgdGhlc2UgbWF4aW11bSBhbmQgbWluaW11bSBwcmljZSB2YWx1ZXMuIFdpdGggdGhpcyBkYXRhLCB3ZSBjcmVhdGVkIHR3byBoaXN0b2dyYW1zOiBvbmUgdGhhdCBkZW1vbnN0cmF0ZXMgdGhlIG9wdGltYWwgYnV5aW5nIHRpbWVzIGZyb20gYSB3b3JsZCBjdXAgZ2FtZSBhbmQgYW5vdGhlciB0aGF0IGRlbW9uc3RyYXRlZCB0aGUgb3B0aW1hbCBzZWxsaW5nIHRpbWVzIGZyb20gYSB3b3JsZCBjdXAgZ2FtZS4gVGhlIGhpc3RvZ3JhbXMgZGlzcGxheSB0aGUgdGltZSBmcm9tIGdhbWUgb24gdGhlIHgtYXhpcyBhbmQgc2hvdyB0aGUgYW1vdW50IG9mIGhhbWVzIHRoYXQgaGF2ZSB0aGVpciBvcHRpbWFsIHNlbGxpbmcgb3IgYnV5aW5nIHRpbWUgYXQgdGhhdCB0aW1lIHZhbHVlLiBGb3IgdGhlIG9wdGltYWwgc2VsbGluZyBoaXN0b2dyYW0sIHRoZXJlIGFyZSBwZWFrcyBhdCAxMCwwMDAgc2Vjb25kcyBhbmQgNSwwMDAgc2Vjb25kcyBiZWZvcmUgdGhlIGdhbWUuIFRoZXNlIHR3byB0aW1lIHZhbHVlcyBjb3JyZXNwb25kIHRvIGFyb3VuZCB0aHJlZSBob3VycyBiZWZvcmUgdGhlIGdhbWUgYW5kIG9uZSBhbmQgYSBoYWxmIGhvdXJzIGJlZm9yZSB0aGUgZ2FtZSwgcmVzcGVjdGl2ZWx5LiBUaGVyZSB3ZXJlIG90aGVyIG91dGxpZXJzIGluIHRoZSBoaXN0b2dyYW0sIGJ1dCB0aGVzZSB0d28gdmFsdWVzIHNlZW0gdG8gYmUgdGhlIGJlc3QgdGltZXMgYXJvdW5kIGEgd29ybGQgY3VwIGdhbWUgdG8gc2VsbCBTUFkgc3RvY2ssIGJhc2VkIG9uIG91ciBkYXRhLiBGb3IgdGhlIG9wdGltYWwgYnV5aW5nIGhpc3RvZ3JhbSwgdGhlcmUgd2FzIGEgbGFyZ2UgcGVhayBhcm91bmQgMTAsMDAwIHNlY29uZHMgYmVmb3JlIHRoZSBnYW1lLCB3aGljaCBpcyB0aHJlZSBob3VycyBiZWZvcmUgdGhlIGdhbWUuIFRoZSBoaXN0b2dyYW0gaXMgc2tld2VkIHJpZ2h0LCBzbyB0aGUgdGltZXMgd2hlcmUgdGhlIFNQWSBwcmljZSB3YXMgdGhlIGxvd2VzdCB3YXMgYmVmb3JlIHRoZSBnYW1lLiBGcm9tIHRoaXMgaGlzdG9ncmFtLCBpdCBhcHBlYXJzIHRoYXQgdGhlIGJlc3QgdGltZSB0byBidXkgU1BZIHN0b2NrIGlzIHRocmVlIGhvdXJzIGJlZm9yZSB0aGUgc3RhcnQgb2YgYSB3b3JsZCBjdXAgZ2FtZS7CoAoKXApcCgojIERvZXMgdGhlIGltcG9ydGFuY2Ugb2YgdGhlIGdhbWUgbWF0dGVyIGluIHRoZSB0b3RhbCBhbW91bnQgb2YgdHJhZGVzPwoKYGBge3J9CiNCb3ggUGxvdCBmb3IgVHJhZGVzCmdncGxvdChhbGxzcHlkYXRhLCBhZXMobG9nKHZvbHVtZSksIFN0YWdlLCBmaWxsID0gU3RhZ2UpKSArIGdlb21fYm94cGxvdCgpICsgZ2d0aXRsZSgiTG9nKFZvbHVtZSkgdnMuIFN0YWdlIE9mIEdhbWUgYW5kIEdyb3VwcyIpCmBgYAoKYGBge3J9CmFsbHNweWRhdGEkU3RhZ2VbZ3JlcGwoIkdyb3VwIiwgYWxsc3B5ZGF0YSRTdGFnZSwgZml4ZWQgPSBUUlVFKV0gID0gIkdyb3VwIgpnZ3Bsb3QoYWxsc3B5ZGF0YSwgYWVzKGxvZyh2b2x1bWUpLCBTdGFnZSwgZmlsbCA9IFN0YWdlKSkgKyBnZW9tX2JveHBsb3QoKSArIGdndGl0bGUoIkxvZyhWb2x1bWUpIHZzLiBTdGFnZSBPZiBHYW1lIikKYGBgCg==